
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib import parse
import subprocess
import pymysql
from urllib.parse import urlencode
import requests
import time

#####
# python3 -u publish_server.py > /var/log/update.log 2>&1 &
# refers:

auth_token = ""
one_time_total = 50000


class ShellHandler(BaseHTTPRequestHandler):
    def do_GET(self):

        # ParseResult(scheme='', netloc='', path='/a/v/b', params='', query='q=1', fragment='')
        parsed_result = parse.urlparse(self.path)
        params = parsed_result.query
        url_path = parsed_result.path

        if not params:
            self.response(401, "Authentication failed")
            return

        param_dict = {}
        for param_pair in params.split('&'):
            print(param_pair)
            key, value = param_pair.split('=')
            param_dict[key] = value

        # auth
        param_token = param_dict.get('token')
        if not param_token or auth_token != param_token:
            self.response(401, "Authentication failed")
            return

        date = param_dict.get('date')
        stock_code = param_dict.get('code')
        price = param_dict.get('price')

        if not date:
            error_msg = "not found all param: date"
            print(error_msg)
            self.response(500, error_msg)
            return
        date = str(date)
        operate_type = 0
        if stock_code == '-':
            stock_code = '0'
            operate_type = 0
            price = 10
        else:
            price = float(price)
            operate_type = price / abs(price)  # -1: in; 1:out
        time_in = 'NULL'
        time_out = 'NULL'
        yield_ = 'NULL'
        price_in = 'NULL'
        price_out = 'NULL'
        if operate_type > 0:  # out
            db_data_in = get_one_record_not_out(stock_code, '')
            print("[out]: search not out data from db by code {}: {}".format(stock_code, db_data_in))
            if db_data_in is None:
                self.response(500, "not found in data from the DB, code: {}\n\n".format(stock_code))
                return
            else:
                db_data_out_price = db_data_in[7]
                if db_data_out_price is not None:
                    self.response(500, "this data from the DB is already out, code: {}, price_out:{}\n\n".format(stock_code, db_data_out_price))
                    return

                time_in = db_data_in[4]
        elif operate_type < 0:
            db_data_in = get_one_record_not_out(stock_code, date)
            print("[in]: search data from db: ", db_data_in)
            if db_data_in is not None:
                self.response(500, "the in data is already in the DB and not out yet, code: {}\n\n".format(stock_code))
                return

        stock_code = str(stock_code)
        stock_name = 'NULL'
        if stock_code != '0':
            data = get_k_history(stock_code, date)
            stock_name = data['name']
        datas, records = get_history_data()
        balance = datas[-1][-1]
        balance = float(balance)
        total_yield = datas[-1][-2]
        real_yield = total_yield
        # total yield
        dict_not_out_price_in = {}
        for record in records:
            this_code = record[2]
            this_price_in = record[5]
            this_price_out = record[7]
            if this_price_out is None:
                # not out
                dict_not_out_price_in[this_code] = this_price_in

        if operate_type > 0:  # out
            this_price_in = dict_not_out_price_in[stock_code]
            this_yield = one_time_total/this_price_in * (price - this_price_in)
            yield_ = this_yield
            total_yield = total_yield + this_yield
            balance = balance + one_time_total + this_yield

            price_out = price
            time_out = date
            dict_not_out_price_in.pop(stock_code)
        elif operate_type < 0:  # in
            price_in = abs(price)
            time_in = date
            balance = balance - one_time_total
            dict_not_out_price_in[stock_code] = price_in
        yield_date = date
        # calc real_yield
        dict_not_out_current_price = {}
        not_out_detail = "\nnot out details: \n"
        for not_out_code in dict_not_out_price_in.keys():
            this_current_price_obj = get_k_history(not_out_code, date)
            this_current_price_in = dict_not_out_price_in[not_out_code]
            if len(this_current_price_obj) > 0:
                this_current_price = float(this_current_price_obj['price'])
                this_name = this_current_price_obj['name']
            else:
                this_current_price = this_current_price_in
                this_name = "NULL"
            dict_not_out_current_price[not_out_code] = this_current_price
            this_current_yield = one_time_total / this_current_price_in * (this_current_price - this_current_price_in)
            print("calc not_out stock: {}, price_in: {}, current_price: {}, current_yield: {}".format(not_out_code, this_current_price_in,
                                                                                                     this_current_price,
                                                                                                     this_current_yield))
            real_yield = real_yield + this_current_yield
            not_out_detail = not_out_detail + "code: %6s, name:%6s, price_in:%5.2f, close_price:%5.2f, yield:%10.2f\n" % (
                not_out_code, this_name, this_current_price_in, this_current_price, this_current_yield
            )

        write_data(operate_type, stock_code, stock_name, time_in, price_in, time_out, price_out, yield_, yield_date, real_yield, total_yield, balance)

        not_out_yield = real_yield - total_yield

        result = "code: {}, name:{}, type: {}, price: {}, date:{}".format(stock_code, stock_name, operate_type, price, date)
        describe = "current yield: {}\nreal yield:{}, total yield:{}, not out yield: {}, balance: {}\n".format(yield_, real_yield, total_yield, not_out_yield, balance)

        self.response(200, str(result + "\n" + describe + not_out_detail))

    def response(self, status, msg):
        self.send_response(status)
        self.send_header('Content-Type',
                         'text/plain; charset=utf-8')
        self.end_headers()
        self.wfile.write(msg.encode('utf-8'))


def gen_secid(rawcode: str) -> str:
    '''
    生成东方财富专用的secid

    Parameters
    ----------
    rawcode : 6 位股票代码

    Return
    ------
    str: 指定格式的字符串

    '''
    # # 沪市指数
    # if rawcode[:3] == '000':
    #     return f'1.{rawcode}'
    # # 深证指数
    # if rawcode[:3] == '399':
    #     return f'0.{rawcode}'
    # 沪市股票
    if rawcode[0] != '6':
        return f'0.{rawcode}'
    # 深市股票
    return f'1.{rawcode}'


def get_k_history_from_db(code: str, date: str):
    db = pymysql.connect(host="192.168.9.156", user="root", password="zdiai@123", db="stock_yield_rate")
    cursor = db.cursor()
    sql_str = "SELECT * from t_stock_history where code={} and date='{}'".format(code, date)
    cursor.execute(sql_str)
    record = cursor.fetchone()
    db.close()
    return record


def save_k_history_to_db(code: str, name: str, date: str, price: float):
    db = pymysql.connect(host="192.168.9.156", user="root", password="zdiai@123", db="stock_yield_rate")
    cursor = db.cursor()
    sql_str = "insert into t_stock_history (code,name, date, price) values('{}','{}','{}', {})".format(code, name, date, price)
    cursor.execute(sql_str)
    db.commit()
    db.close()


def get_k_history(code: str, date: str, klt: int = 101, fqt: int = 0):
    '''
    功能获取k线数据

    Parameters
    ----------
    code : 6 位股票代码
    date: 开始日期 例如 20200101
    klt: k线间距 默认为 101 即日k
        klt:1 1 分钟
        klt:5 5 分钟
        klt:101 日
        klt:102 周
    fqt: 复权方式
        不复权 : 0
        前复权 : 1
        后复权 : 2
    Return
    ------
    DateFrame : 包含股票k线数据
    '''
    #  {'code': '600372', 'name': '中航电子', 'date': '2021-05-14', 'price': '15.47'}
    # price_obj = get_k_history(code, date)
    # if price_obj is not None:
    #     return {'code': code, 'name': price_obj[2], 'date': date, 'price': price_obj[4]}
    print("Begin to get data from EM: {}, {}".format(date, code))

    EastmoneyKlines = {
        'f51': '日期',
        'f53': '收盘'


    }
    EastmoneyHeaders = {
        'Host': '19.push2.eastmoney.com',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko',
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        'Referer': 'http://quote.eastmoney.com/center/gridlist.html',
    }
    fields = list(EastmoneyKlines.keys())
    columns = list(EastmoneyKlines.values())
    fields2 = ",".join(fields)
    secid = gen_secid(code)
    params = (
        ('fields1', 'f1,f2,f3,f4,f5,f6'),
        ('fields2', fields2),
        ('beg', date),
        ('end', '20500101'),
        ('rtntype', '6'),
        ('secid', secid),
        ('klt', f'{klt}'),
        ('fqt', f'{fqt}'),
        ('lmt', f'{120}'),
        ('_', f'{int(time.time() * 1000)}')
    )
    params = dict(params)
    base_url = 'https://push2his.eastmoney.com/api/qt/stock/kline/get'
    url = base_url+'?'+urlencode(params)
    json_response: dict = requests.get(
        url, headers=EastmoneyHeaders).json()

    data = json_response.get('data')
    if data is None:
        if secid[0] == '0':
            secid = f'1.{code}'
        else:
            secid = f'0.{code}'
        params['secid'] = secid
        url = base_url+'?'+urlencode(params)
        json_response: dict = requests.get(
            url, headers=EastmoneyHeaders).json()
        data = json_response.get('data')
    if data is None:
        print('股票代码:', code, '可能有误')
        return {}

    # klines = data['klines']
    #
    # rows = []
    # for _kline in klines:
    #
    #     kline = _kline.split(',')
    #     rows.append(kline)
    #
    # df = pd.DataFrame(rows, columns=columns)
    stock_name = data['name']
    # print("all datas: ", data)
    for price_str in data['klines']:
        price_array = price_str.split(',')
        t_date, t_price = price_array[0], price_array[1]
        if t_date == date:
            this_data = {'code': code, 'name': stock_name, 'date': t_date, 'price': t_price}
            print("get data from EastMoney: ", this_data)
            return this_data
    print("not found {} @ {} in {} klines data.".format(code, date, len(data['klines'])))
    return {}


def get_one_record_not_out(code: str, date: str):
    db = pymysql.connect(host="192.168.9.156", user="root", password="zdiai@123", db="stock_yield_rate")
    cursor = db.cursor()
    sql_str = "SELECT * from t_operate_record where stock_code={} and time_out is NULL".format(code)
    if not date and date != '':
        sql_str = sql_str + " and time_in='{}'".format(date)
    print(sql_str)
    cursor.execute(sql_str)
    record = cursor.fetchone()
    db.close()
    return record

def get_history_data():
    db = pymysql.connect(host="192.168.9.156", user="root", password="zdiai@123", db="stock_yield_rate")
    cursor = db.cursor()
    cursor.execute("SELECT * from t_yield_rate order by id desc limit 1")
    data = cursor.fetchall()
    cursor.execute("SELECT * from t_operate_record")
    records = cursor.fetchall()
    db.close()
    return data, records


def write_data(operate_type, stock_code, stock_name, time_in, price_in, time_out, price_out, yield_, yield_date, real_yield, total_yield, balance):
    print("write data: ", operate_type, stock_code, stock_name, time_in, price_in, time_out, price_out, yield_, total_yield, balance)
    sql_str = ''
    if operate_type < 0:  # in
        sql_str = "INSERT INTO stock_yield_rate.t_operate_record (update_time, stock_code, stock_name, time_in, price_in, time_out, price_out, yield) VALUES (" \
              "NOW(), '{}', '{}', '{}', {}, NULL, NULL, NULL)".format(stock_code, stock_name, time_in, price_in)
    elif operate_type > 0:  # out
        sql_str = "update stock_yield_rate.t_operate_record set update_time=NOW(), time_out='{}', price_out={}, yield={} where stock_code={} and time_in='{}'"\
            .format(time_out, price_out, yield_, stock_code, time_in)

    db = pymysql.connect(host="192.168.9.156", user="root", password="zdiai@123", db="stock_yield_rate")
    cursor = db.cursor()
    sql_str_line = "INSERT INTO stock_yield_rate.t_yield_rate (update_time, yield_date, real_yield, total_yield, balance) VALUES (NOW(),'{}', {}, {}, {})".format(yield_date, real_yield, total_yield, balance)

    if sql_str != '':
        print("exec ", sql_str)
        cursor.execute(sql_str)
    print("exec ", sql_str_line)
    cursor.execute(sql_str_line)
    db.commit()
    db.close()


def exec_command(command):
    result = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output = result.communicate()[0]
    return result.returncode, output


def run(server_class=HTTPServer, handler_class=ShellHandler):
    server_address = ('', 18100)
    httpd = server_class(server_address, handler_class)
    print("starting publish service...")
    httpd.serve_forever()


if __name__ == '__main__':
    with open("auth-token.txt", "r") as file:
        token = file.readline()
        if token:
            auth_token = str(token.replace('\n', ''))
    if not auth_token:
        print("Error: auth_token is not set.")
    run()

    # get_k_history('600366', '2021-01-04')









